package com.zyq.validation.controller;

import com.zyq.validation.exception.AgeOutOfRangeException;
import com.zyq.validation.pojo.entity.*;
import com.zyq.validation.validator.AgeBetweenValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//@RestController注解的含义是当前控制器类中每个控制器方法
// 都默认添加@ResponseBody注解
// SpringMvc框架会自动将@ResponseBody注解标记的方法的返回值转换为json格式
@Slf4j
@RestController
public class TestController {
    @PostMapping(value = "/reg")
    public User test(@Validated User user){//index.html访问出来后提交数据就会报400的异常，提示名字字符过多，年龄超过限制
        return user;
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new AgeBetweenValidator());
    }

    @RequestMapping(value = "/reg1", produces = "application/json;charset=UTF-8")
    public User1 test1(@RequestBody @Validated User1 user, BindingResult result){
        /*DataBinder binder = new DataBinder(user);//校验器包含user
        binder.setValidator(new AgeBetweenValidator());//给校验器设置校验规则
        // validate the target object
        binder.validate();//校验

        // get BindingResult that includes any validation errors
        BindingResult results = binder.getBindingResult();//获取校验结果信息
        log.info("results:{}", results);*/

        // 参数校验
        if (result.hasErrors()) {
            List<FieldError> fieldErrors = result.getFieldErrors();
            fieldErrors.forEach(e -> {
                System.out.println(e.getField() + e.getCode());
            });
            throw new AgeOutOfRangeException("年龄数值超范围异常[1,239]","age",user.getAge()+"");
        }
        return user;
    }//https://app.apifox.com/project/4524520


    //RequestBody: 将请求体中的数据映射到方法的参数上(用于接收post请求发送的请求体的数据)
    //test2方法需要用postman或apifox 或者ajax的方式提交数据来访问(不能用html的form表单的action提交参数)
    //因为html的form表单的action提交方式的Content-type的值是'application/x-www-form-url (而且无法修改<我目前掌握的知识无法修改它>)
    //可以将form表单的数据改用ajax方式提交数据
    @PostMapping(value = "/reg2", produces = "application/json;charset=UTF-8")
    public User test2(@RequestBody @Validated User user){
        return user;//index.html访问出来后提交数据就会报400的异常，提示名字字符过多，年龄超过限制
    }//https://app.apifox.com/project/4524520


    @PostMapping(value = "/reg3", produces = "application/json;charset=UTF-8")
    public Customer test3(@RequestBody @Validated Customer customer){
        return customer;
    }//https://app.apifox.com/project/4524520

    @RequestMapping(value = "/reg4", produces = "application/json;charset=UTF-8")
    public User2 test4(@RequestBody @Validated(User2.group1.class) User2 user){
        return user;
    }//https://app.apifox.com/project/4524520

    @RequestMapping(value = "/reg5", produces = "application/json;charset=UTF-8")
    public User2 test5(@RequestBody @Validated(User2.group2.class) User2 user){
        return user;  //test5方法只会对第二个分组group2的字段进行校验，其他字段不会进行校验////////////////////////////////////////////////////
    }//https://app.apifox.com/project/4524520

    @RequestMapping(value = "/reg6")
    public Student test5(@Validated Student student){
        return student;
    }//https://app.apifox.com/project/4524520

    @RequestMapping(value = "/reg6", produces = "application/json;charset=UTF-8")
    public User test6(@RequestBody @Validated User user, BindingResult bindingResult){
    //注意：如果对于单个参数进行 校验的话@Valid和@Validated是一样的。 但如果要进行分组校验则需要用到@Validated
        if(bindingResult.hasErrors()){//这个if用来打印校验不通过的提示信息的(可以将这些代码提取到统一异常处理类GlobalException中)
            List<ObjectError> list=bindingResult.getAllErrors();
            for(ObjectError objectError:list){
                log.info(objectError.getCode()+"::"+objectError.getDefaultMessage());
            }
        }

        return user;
    }//https://app.apifox.com/project/4524520

    @RequestMapping(value = "/reg7", produces = "application/json;charset=UTF-8")
    public User3 test7(@RequestBody @Validated User3 user){
        return user;
    }//https://app.apifox.com/project/4524520


}

//@RequestBody注解解释：
//@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的,所以只能接收post方式数据)；
//在后端的同一个接收方法里，@RequestBody与@RequestParam()可以同时使用，@RequestBody最多只能有一个，而@RequestParam()可以有多个。
//注：一个请求，只有一个RequestBody；一个请求，可以有多个RequestParam。
//注：当同时使用@RequestParam（）和@RequestBody时，@RequestParam（）指定的参数可以是普通元素、
//数组、集合、对象等等(即:当，@RequestBody 与@RequestParam()可以同时使用时，原SpringMVC接收
//参数的机制不变，只不过RequestBody 接收的是请求体里面的数据；而RequestParam接收的是key-value
//里面的参数，所以它会被切面进行处理从而可以用普通元素、数组、集合、对象等接收)。
//即：如果参数时放在请求体中，传入后台的话，那么后台要用@RequestBody才能接收到；如果不是放在
//请求体中的话，那么后台接收前台传过来的参数时，要用@RequestParam来接收，或则形参前
//什么也不写也能接收。
//
//注：如果参数前写了@RequestParam(xxx)，那么前端必须有对应的xxx名字才行(不管其是否有值，当然可以通
//过设置该注解的required属性来调节是否必须传)，如果没有xxx名的话，那么请求会出错，报400。
//
//注：如果参数前不写@RequestParam(xxx)的话，那么就前端可以有可以没有对应的xxx名字才行，如果有xxx名
//的话，那么就会自动匹配；没有的话，请求也能正确发送。


/*
{
    "userName": "fdaffdsfds",
    "age": "-3",
    "pwd":"3432432"
}

* */